package basic

import java.lang.Exception
import kotlin.properties.Delegates
import kotlin.reflect.KProperty

/*fun main(args: Array<String>) {
    foo()
}*/


fun  lable(){
    loop@ for (i in 1..100){
        for (j in 1..10){
            println("相加的数${i+j}")
            if(i+j>10) break@loop
        }
    }
}

fun foo(){
    listOf(1,2,3,4,5,6).forEach lit@ {
        if ( it == 3 ) return@lit
        println("msg:${it}")
    }
    println(" done with explicit label")
}


fun parseInt(str:String):Int?{
    return  str.toIntOrNull()
}

//显示类型转换  is 运算符检测一个表达式是否某类型的一个实例
fun getStringLength(obj:Any):Int?{
    if(obj is String && obj.length>0){
        return  obj.length
    }
    return  null
}

//使用 in 运算符来检测某个数字是否在指定区间内[...(downTo)]
fun useIn(num:Int):Boolean{
    if(num in 10..60){
        return  true
    }
    return  false
}

//使用字符串模板
fun strTemplate(){
    val egStr="helloWord"
    print("$egStr length is ${egStr.length}")
}

//constructor     主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化块
class  Person constructor(firstName:String){
    val name="First Name is $firstName".also { print(firstName) }
    init {
        println("First $name");
    }
    val upCase=firstName.toUpperCase();
    init {
        println("upCase $upCase")
    }
}

//主次构造函数的委托 委托到同一个类的另一个构造函数用 this 关键字即可
class User(name:String){
    constructor(name:String,user:User):this(name){
       println("name $name")
    }
}



open   class  Base(isOrNot:Boolean){
    open fun method(){
        println("base method")
    }
    fun  ov(){
        println("base ov")
    }

    open  val  x:Int
        get() {return 5}

}

class  Child :Base{
    constructor(isOrNot: Boolean):super(isOrNot)

    override fun method() {
        super.method()
    }
    //var 属性覆盖一个 val 属性，但反之则不行。这是允许的，因为一个 val 属性本质上声明了一个 getter 方法，而将其覆盖为 var 只是在子类中额外声明一个 setter 方法。
    override val x: Int
        get() = super.x
}



//类初始化的流程==>
class  Xbase(val name: String){
    init {
        println("print Xbase")
    }

    open  val size:Int=name.length.also { println() }
}



//实现继承由下述规则规定：如果一个类从它的直接超类继承相同成员的多个实现， 它必须覆盖这个成员并提供其自己的实现（也许用继承来的其中之一）。 为了表示采用从哪个超类型继承的实现，我们使用由尖括号中超类型名限定的 super，如 super<Base>

open class  A {
    open  fun  f(){
        println("class A f()")
    }
    fun a(){
        println("class A a()")
    }
}

interface  B{
    open  fun  f(){
        println("interface B f()")
    }

    fun  b(){
        println("interface B b()")
    }
}

class  C() :A(),B{
    override fun f() {
        super<A>.f()//需要指定f()的访问
        super<B>.f()
    }
}



//var val（只读，没有setter）

class  Address{
    var name:String
    get() = this.toString()
    set(value) {
        name=value;
    }

    val isEmpty get() = this.name.length==0

}


//数据类的使用 并标记为 data
data  class  UserDate(val name: String,val age:Int);



//泛型的使用
 class Box<T>(t:T){
    var value=t;
}
/*val box:Box<Int> = Box<Int>(2);
val box= Box(1);*/


//内部类 ：类可以标记为 inner 以便能够访问外部类的成员。内部类会带有一个对外部类的对象的引用

class  Outer{
    private  val bar :Int=1;
    inner  class  Inner{
        fun foo()=bar;
    }
}
val demo= Outer().Inner().foo();


//对象的使用
fun foos(){
    val daHoc=object {
        var x:Int=5;
        var Y:Int=6;
    }
    print(daHoc.x+daHoc.Y)
}


//匿名对象可以用作只在本地和私有作用域中声明的类型  作为共有函数返回的是Any

class  TestClass{
    private  fun  fooToPrivate()=object {
        val x:Int=5;
    }
    fun fooToOpen()=object {
        val x:Int=6;
    }

    fun printX(){
        val x1=fooToPrivate().x;//可以调用
        //val x2=fooToOpen().x; //不能调用 返回的是Any
    }
}


//伴生对象的使用 类内部的对象声明可以用 companion 关键字标记
//作用：在Java中有static关键字表示静态成属性和方法，但在Kotlin中没有static关键字，所以伴生对象和顶层函数一起来弥补了这一缺憾
class MyClass{
    companion object Factory{
        fun  create():MyClass= MyClass();
    }
}

//调用
val instance=MyClass.create();



class TestCompanion{
    companion object  CompanionObj{
        fun  companionFun(){
            print("companionFun println")
        }
        val companionParma:Int=5;
    }
}

//调用
/*fun main(args: Array<String>) {
    println( TestCompanion.companionParma)
    TestCompanion.companionFun()
}*/


//类型别名 使用typealias关键字
typealias  Predicate<T> = (T) -> Boolean

fun  foo(d:Predicate<Int>)=d(42)

/*fun main(args: Array<String>) {
   val f:(Int)->Boolean={it>0}
    println(foo(f))
    val p: Predicate<Int> = { it > 0 }
    println(listOf(1, -2).filter(p))
}*/


//内联类 使用inline关键字修饰的类  定义：
//限制:1.不包含init代码块   2.不含有幕后字段（只能含有简单的计算属性，不含有延迟初始化/委托属性）


inline class Password(val value: String)
/*fun main(args: Array<String>) {
    var mPassword=Password("hao199508280")
    println(mPassword.value)
}*/
//不能参与类的继承关系结构中，只能实现接口
interface  Printable{
    fun  Print():String
}

inline class  PrintName(val  name:String) :Printable{
    override fun Print(): String {
       return  "My name is $name"
    }
}

/*fun main(args: Array<String>) {
   var mPrintName= PrintName("xiaohao")
    println(mPrintName.Print())
}*/

//委托
//作用：实现继承的一个很好的替代方式

interface  BaseInterface{
  fun  print()
}

class  BaseIml (val x:Int):BaseInterface{
    override fun print() {
        println(x)
    }
}

//委托类
// by-子句表示 b 将会在 Derived 中内部存储， 并且编译器将生成转发给 b 的所有 Base 的方法
class  Derived(b:BaseInterface):BaseInterface by b

/*
fun main(args: Array<String>) {
    val b=BaseIml(100)
    Derived(b).print()
}
*/


//eg 2
interface  BaseClass{
    fun  printMessage();
    fun  printMessageLine();
}

class BaseClassIml(val x:Int):BaseClass{
    override fun printMessage() {
       println("printMessage $x")
    }
    override fun printMessageLine() {
       println("printMessageLine $x")
    }
}

//委托类
class  Deriveds(b:BaseClass):BaseClass by  b{
    override fun printMessage() {
        println("abc")
    }
}

/*fun main(args: Array<String>) {
    val b=BaseClassIml(100)
    Deriveds(b).printMessage()
    Deriveds(b).printMessageLine()
    //输出：
    //abc
    //printMessageLine 100
    //委托类使用自生的override而不是委托对象的
}*/


//委托属性
class  Example{
    var p:String by Delegate()
}

class  Delegate{
    operator fun getValue(example:Any?, property: KProperty<*>): String {
        return  "$example--> ${property.name}"
    }

    operator fun setValue(example: Any?, property: KProperty<*>, s: String) {
        println("$example --> ${property.name} -->$s")
    }
}

/*fun main(args: Array<String>) {
   val mExample:Example= Example();
    println(mExample.p)
    mExample.p="小浩"
    println(mExample.p)

    //输出
    //basic.Example@433c675d--> p
    //basic.Example@433c675d --> p -->小浩
    //basic.Example@433c675d--> p
}*/


//延迟属性   第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果
val lazyValue :String by lazy<String> {
    println("dididi")
    "aaa"
}

/*fun main(args: Array<String>) {
    println(lazyValue)
    println(lazyValue)
    //输出
    //dididi
    //aaa
    //aaa
}*/

//可观察属性  Delegates.observable()
class  UserDelegates{
    var name:String by Delegates.observable("<initialVal>"){
        _, oldValue, newValue ->
        println("$oldValue--->$newValue")
    }
}

/*fun main(args: Array<String>) {
   val mUserDelegates=UserDelegates();
    mUserDelegates.name="小明"
    mUserDelegates.name="小化"
    //输出：
    //<initialVal>--->小明
    //小明--->小化
}*/

//Delegates.vetoable()使用  在属性被赋新值生效之前会调用传递给 vetoable 的处理程序
class  UserVetoable{
    var age:Int by Delegates.vetoable(6){
        _, oldValue, newValue ->
        if(newValue>oldValue) true else throw  IllegalAccessException("新值必须要大于旧值")
    }
}
/*fun main(args: Array<String>) {
   val mUserDelegates=UserVetoable();
    println(mUserDelegates.age)
    mUserDelegates.age=10
    println(mUserDelegates.age)
    try {
        mUserDelegates.age=5
    }catch (e:Exception){
        println(e.toString())
    }
    //输出：
    //6
    //10
    //java.lang.IllegalAccessException: 新值必须要大于旧值
}*/

//把属性储存在映射中
class  UserMap(val map:Map<String,Any?>){
    val name:String by map
    val age:Int by map
}
/*
fun main(args: Array<String>) {
   val user:UserMap= UserMap(mapOf("name" to  "xiaohao","age" to  15))
    println("user Info: ${user.name}")
}*/


//函数与Lambda学习
//方法
//需要注意的 1.当覆盖一个带有默认参数值的方法时，必须省略默认参数值

open  class  AClass{
    open fun foo(i:Int=10){
        println("AClass $i")
    }
}

class  bClass:AClass(){
    override fun foo(i: Int) {
        println("bClass ==> ${i+1} ")
    }
}

//2.如果一个函数有一个默认值参数和一个形参，则传入形参的时候需要使用命名参数进行赋值
fun functionTest(a:Int=5,b:String){
    println("a is $a ,b is $b")
}

/*fun main(args: Array<String>) {
    functionTest(b="我是第二个参数");
}*/

//可变参数：可以通过使用星号操作符将可变数量参数（vararg） 以命名形式传入
fun functionArg(vararg a:String ){
    println("vararg ${a[0]}")
}
//结合泛型使用
fun <T> asList(vararg  arg:T):List<T>{
    val result= ArrayList<T>()
    for (a in arg){
        result.add(a)
    }
    return  result
}

/*fun main(args: Array<String>) {
    functionArg(a=*arrayOf("第一个","第二个","收尾"));
    //伸展（spread）操作符（在数组前面加 *）
    var strList= arrayOf(1,3,5)
    var list=asList(1,"dw",*strList,3)
    println(list.toString())//输出 ：[1, dw, 3]
}*/

//单函数表达式
fun  double(x:Int):Int=x+5;
//===>可以简写成 fun double(x:Int)=x+5;  返回值类型可由编译器推断


//函数 中缀表示法
//定义：标有 infix 关键字的函数也可以使用中缀表示法
//作用：忽略该调用的<点与圆括号>
//条件：1.必须是成员函数或者扩展函数 2.只能有一个参数（不能为可变参数） 参数不能有默认值 2.中缀函数总是要求指定接收者与参数
//eg :求两个集合的交集（扩展函数）


//===> 优化前
fun <T> List<T>.getIntersection(otherArr:List<T>):List<T>{
    var resultArr=ArrayList<T>()
    forEach{
        if(otherArr.contains(it)){
            resultArr.add(it)
        }
    }
    return  resultArr
}

//===> 优化后 使用n为函数名 （去掉之后更直观）
infix  fun <T> List<T>.n(otherArr:List<T>):List<T>{
    var resultArr=ArrayList<T>()
    forEach{
        if(otherArr.contains(it)){
            resultArr.add(it)
        }
    }
    return  resultArr
}


/*
fun main(args: Array<String>) {
    var listArr= arrayOf(1,2,3,4,5,6,7,8)
    var otherArr= arrayOf(3,4,5,6)
    //常规使用扩展函数
    listArr.toList().getIntersection (otherArr.toList())
    //使用中缀函数
    listArr.toList() n (otherArr.toList())
}
*/


//Elvis 操作符
fun testNull(node:String?):Int{
    val legth=node?.length?:-1
    return  legth
}
/*fun main(args: Array<String>) {
    var len=testNull(null)
    println(len)
}*/

//!! 操作符  (非空断言运算符)
var b="adawd"
val l = b!!.length


fun isOdd(x: Int) = x % 2 != 0
val numbers = listOf(1, 2, 3)

fun main(args: Array<String>) {
    var test=TestJava()
    test.test()
}












